#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/PrintLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/SimpleFileSystem.h>

EFI_STATUS
TestWrite(EFI_FILE_PROTOCOL *Root)
{
  EFI_STATUS Status         = EFI_SUCCESS;
  UINTN BufferSize          = 0;
  CHAR16 *FileName          = L"ReadMe";
  EFI_FILE_PROTOCOL *ReadMe = NULL;
  CHAR16 WriteBuffer[]      = L"This is a test file.\r\n";

  Status = Root->Open(Root, &ReadMe, FileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
  if (EFI_ERROR(Status)) {

    Print(L"Root->Open() %r\n", Status);
    return Status;
  }

  BufferSize = sizeof(WriteBuffer);
  Status     = ReadMe->Write(ReadMe, &BufferSize, WriteBuffer);
  if (EFI_ERROR(Status)) {

    Print(L"ReadMe->Write() %r\n", Status);
    return Status;
  }

  Status = ReadMe->Close(ReadMe);

  return Status;
}

EFI_STATUS
TestRead(EFI_FILE_PROTOCOL *Root)
{
  EFI_STATUS Status         = EFI_SUCCESS;
  UINTN BufferSize          = 0;
  CHAR16 *FileName          = L"ReadMe";
  EFI_FILE_PROTOCOL *ReadMe = NULL;

  CHAR16 ReadBuffer[100];
  ZeroMem(ReadBuffer, sizeof(ReadBuffer));

  Status = Root->Open(Root, &ReadMe, FileName, EFI_FILE_MODE_READ, 0);
  if (EFI_ERROR(Status)) {

    Print(L"Root->Open() %r\n", Status);
    return Status;
  }

  BufferSize = sizeof(ReadBuffer);
  Status     = ReadMe->Read(ReadMe, &BufferSize, ReadBuffer);
  if (EFI_ERROR(Status)) {

    Print(L"ReadMe->Read() %r\n", Status);
    return Status;
  }

  Print(L"Read %d bytes: %s", BufferSize, ReadBuffer);

  Status = ReadMe->Close(ReadMe);

  return Status;
}

EFI_STATUS
UefiMain(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
{
  EFI_FILE_PROTOCOL *Root                           = NULL;
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem = NULL;
  EFI_STATUS Status                                 = EFI_SUCCESS;

  Status = gBS->LocateProtocol(&gEfiSimpleFileSystemProtocolGuid, NULL, (VOID **)&SimpleFileSystem);
  if (EFI_ERROR(Status)) {

    Print(L"LocateProtocol() %r\n", Status);
    return Status;
  }

  Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &Root);
  if (EFI_ERROR(Status)) {

    Print(L"OpenVolume() %r\n", Status);
    return Status;
  }

  TestWrite(Root);
  TestRead(Root);

  return Status;
}